/* Includes ------------------------------------------------------------------*/
#include <main.h>

/* Private define-------------------------------------------------------------*/

/* Private variables----------------------------------------------------------*/
#define TCP_Server "AT+CIPSTART=\"TCP\",\"172.29.168.77\",8888\r\n"  //电脑端模拟的TCP服务器
//#define TCP_Server "AT+CIPSTART=\"TCP\",\"172.29.168.66\",8888\r\n"  //手机端模拟的TCP服务器

static void Init(void);                     //WIFI模块初始化
static void SmartConfig(void);              //WIFI模块配网
static void TCP_Connect_Server(void);       //通过TCP连接服务器
static void Transfer_Tempareture(float );   //传送PCB板的温度
static void Receive_Information(void);      //接收信息

static void SendAT(uint8_t* ,uint8_t* );    //发送AT指令
/* Public variables-----------------------------------------------------------*/
ESP8266_t idata ESP8266 = 
{
  FALSE,
  TIMER_10S,

  Init,
  SmartConfig,
  TCP_Connect_Server,
  Transfer_Tempareture,
  Receive_Information
};
/* Private function prototypes------------------------------------------------*/

/*
* @name   Init
* @brief  ESP8266初始化
* @param  None
* @retval None   
*/
static void Init()
{
    //复位模块
    WIFI_RST = 0;
    Public.Delay_ms(100);
    WIFI_RST = 1;

    //使能模块
    WIFI_EN = 1;

    //同步波特率
    Timer0.usDelay_Timer = 0;
    do
    {
      //清除串口2的接收缓存
      Public.Memory_Clr(UART2.pucRec_Buffer,UART2.ucRec_Cnt);
      UART2.ucRec_Cnt = 0;
      //发送AT指令测试与WiFi模块的通信情况
      UART2.UART_SendString("AT\r\n");
      Public.Delay_ms(100);

      #ifdef Monitor_Run_Code
      /*打印ESP-12S上电时的乱码、ready，以及发送“AT”指令后，ESP-12S回复的“AT”+“OK”
		  因为接收数组可接收100个字节，所以一长串的乱码信息也足够存储*/
        printf(UART2.pucRec_Buffer);
      #endif
      
      //喂狗
      WatchDog.Feed();

      /*下面while语句如果一直为真，则表示接收数组没有收到OK应答，表示与WIFI模块的通信出问题
      这里进行检测，如果超过10s仍没有通信成功，则进行超时处理*/
      if(Timer0.usDelay_Timer > TIMER_10S)
      {
        Public.Error_Handler();
        break;
      }
    } while (strstr(UART2.pucRec_Buffer,"OK") == NULL);
}

/*
* @name   SendAT
* @brief  发送AT指令
* @param  AT_Command：待发送的AT指令
          Respond_Str：回应数据中包含的字符串
* @retval None   
*/
static void SendAT(uint8_t* AT_Command,uint8_t* Respond_Str)
{
  uint8_t* const xdata Ptr_AT_Command   = AT_Command;
  uint8_t* const xdata Ptr_Respond_Str  = Respond_Str;

  //清除串口2的接收缓存
  Public.Memory_Clr(UART2.pucRec_Buffer,UART2.ucRec_Cnt);
  UART2.ucRec_Cnt = 0;

  //发送AT指令
  UART2.UART_SendString(Ptr_AT_Command);

  //打印一次发送的命令
  #ifdef Monitor_Run_Code
    printf(Ptr_AT_Command);
  #endif

  //等待模块回应数据，超时错误处理
  Timer0.usDelay_Timer = 0;
  while(strstr(UART2.pucRec_Buffer,"\r\n") == NULL)
  {
    //喂狗
    WatchDog.Feed();

    if(Timer0.usDelay_Timer > TIMER_100MS)
    {
      Public.Error_Handler();
      break;
    }
  }
  
  //延时10ms，接收全部字节
  Public.Delay_ms(10);

  //如果模块回应的数据不是想要的，则进行错误处理
  if(strstr(UART2.pucRec_Buffer,Ptr_Respond_Str) == NULL)
  {
      Public.Error_Handler();
  }

  /*打印接收数组收到的应答，AT和ATE0指令会返回指令和“OK”应答，AT+CWMODE_CUR=1指令则只会返回“OK”
	加上上面打印了发送的指令，所以发送AT和ATE0指令的话，在串口会看到连续打印了两次AT和两次ATE0，
	发送AT+CWMODE_CUR=1则上面语句打印该条指令，接收数组打印的是“OK”应答*/
  #ifdef Monitor_Run_Code
    printf(UART2.pucRec_Buffer);
  #endif

  //清除串口2的接收缓存
  Public.Memory_Clr(UART2.pucRec_Buffer,UART2.ucRec_Cnt);
  UART2.ucRec_Cnt = 0;
}

/*
* @name   SmartConfig
* @brief  WIFI模块配网
* @param  None
* @retval None   
*/
static void SmartConfig()
{
  //检测到按键2长按标志位置位，进入配网模式
  if(KEY2.Press == TRUE)
  {
    //如果TCP连接状态位为真，则表示已经连接服务器并开启透传模式
    if(ESP8266.TCP_Connect_Status == TRUE)
    { 
      //先关闭透传模式
      // UART2.UART_SendData('+');
      // UART2.UART_SendData('+');
      // UART2.UART_SendData('+');
      UART2.UART_SendString("+++");   //也能这样发送退出透传模式
      Public.Delay_ms(1000);      //延时1秒，手册建议
    }
    //喂狗
    WatchDog.Feed();

    //如果没连接服务器或者透传模式已经关闭，则进行配网
    SendAT("AT\r\n","OK");                  //测试AT指令
    SendAT("ATE0\r\n","OK");                //关闭回显
    SendAT("AT+CWMODE_CUR=1\r\n","OK");     //WIFI模块设置为STA模式
    SendAT("AT+CWAUTOCONN=1\r\n","OK");     //上电自动连接到AP，模块默认会自动连接
    SendAT("AT+CWSTARTSMART\r\n","OK");     //开启SmartConfig(SmartConfig类型为ESP-Touch + AirKiss)

    #ifdef Monitor_Run_Code
      printf("Start SmartConfig!\r\n");
    #endif

    //等待微信配网，超过3分钟则退出
    Timer0.usDelay_Timer = 0;
    while (Timer0.usDelay_Timer < TIMER_3MIN)
    {
      //喂狗
      WatchDog.Feed();

      Public.Delay_ms(100);
      Run_LED.Run_LED_Flip();

      if(strstr(UART2.pucRec_Buffer,"Smart get wifi info") != NULL)
      {
        //延时6秒，WIFI模块处理信息
        //同时要不断喂狗，防止系统重启
        WatchDog.Feed();
        Public.Delay_ms(1000);
        WatchDog.Feed();
        Public.Delay_ms(1000);
        WatchDog.Feed();
        Public.Delay_ms(1000);
        WatchDog.Feed();
        Public.Delay_ms(1000);
        WatchDog.Feed();
        Public.Delay_ms(1000);
        WatchDog.Feed();
        Public.Delay_ms(1000);
        WatchDog.Feed();
        //SendAT("AT+CWSTOPSMART\r\n","OK"); //停止SmartConfig
				//配网后，系统复位会复位WIFI模块，可以不执行停止SmartConfig指令
        break;
      }

      #ifdef Monitor_Run_Code
        printf(UART2.pucRec_Buffer);
      #endif
    }
    //配网成功，系统复位
    Public.Sys_Soft_Reset();
  }
}

/*
* @name   TCP_Connect_Server
* @brief  通过TCP连接客户端
* @param  None
* @retval None   
*/
static void TCP_Connect_Server()
{
  SendAT("AT\r\n","OK");                //测试AT指令
  SendAT("ATE0\r\n","OK");              //关闭回显
  SendAT("AT+CWMODE_CUR=1\r\n","OK");   //WIFI模块设置为STA模式

  //喂狗
  WatchDog.Feed();

  //获取IP
  Timer0.usDelay_Timer = 0;
  do
  {
    //清除串口2的接收缓存
    Public.Memory_Clr(UART2.pucRec_Buffer,UART2.ucRec_Cnt);
    UART2.ucRec_Cnt = 0;

    //获取WIFI模块的IP地址
    UART2.UART_SendString("AT+CIFSR\r\n");
    Public.Delay_ms(1000);

    //打印串口2接收到的应答
    #ifdef Monitor_Run_Code
      printf(UART2.pucRec_Buffer);
    #endif

    //超过10s没有获取到IP地址，则跳出循环
    if(Timer0.usDelay_Timer > TIMER_10S)
    {
      break;
    }
  /*如果获取的IP信息一直有0.0.0.0则满足!= NULL 的条件，回到上面继续发AT+CIFSR指令
  如果获取到局域网IP地址，则接收数组内没有0.0.0.0，则strstr返回NULL，不满足条件，退出循环
  */
  } while (strstr(UART2.pucRec_Buffer,"0.0.0.0") != NULL);
  
  //等待稳定连接到AP
  Timer0.usDelay_Timer = 0;
  do
  {
    //清除串口2的缓存
    Public.Memory_Clr(UART2.pucRec_Buffer,UART2.ucRec_Cnt);
    UART2.ucRec_Cnt = 0;

    UART2.UART_SendString("AT\r\n");
    Public.Delay_ms(100);

    //打印串口2接收到的应答
    #ifdef Monitor_Run_Code
      printf(UART2.pucRec_Buffer);
    #endif

    //超过10s没有同步，进行错误处理
    if(Timer0.usDelay_Timer > TIMER_10S)
    {
      Public.Error_Handler();
      break;
    }
    //如果接收到Ok应答，则退出循环；没有接收到OK，则继续发送AT指令
  } while (strstr(UART2.pucRec_Buffer,"OK") == NULL);
  
  //连接服务器
  #ifdef Monitor_Run_Code
      printf("Connect TCP Server!\r\n");
  #endif

  Timer0.usDelay_Timer = 0;
  do
  {
    //清除串口2的接收缓存
    Public.Memory_Clr(UART2.pucRec_Buffer,UART2.ucRec_Cnt);
    UART2.ucRec_Cnt = 0;

    //发送要连接的服务器地址和端口号
    UART2.UART_SendString(TCP_Server);
    Public.Delay_ms(100);

    //超过5s还没有连接上服务器
    if(Timer0.usDelay_Timer > TIMER_5S)
    {
      //打印连接服务器失败提示
      #ifdef Monitor_Run_Code
        printf("Connect TCP Server Failure!\r\n");
      #endif
      //连接标志位置0
      ESP8266.TCP_Connect_Status = FALSE;
      break;
    }

    //连接到服务器
    //如果成功连接，模块会返回	
		/*
		busy p...    				
		CONNECT       
		OK
		*/
    if(strstr(UART2.pucRec_Buffer,"CONNECT") != NULL)
    {
      //打印连接服务器失败提示
      #ifdef Monitor_Run_Code
        printf("Connect TCP Server Success!\r\n");
      #endif
      //连接标志位置1
      ESP8266.TCP_Connect_Status = TRUE;
      break;
    }
  } while (strstr(UART2.pucRec_Buffer,"CONNECT") == NULL);
  
  //使能透传模式
  if(ESP8266.TCP_Connect_Status == TRUE)
  {
    SendAT("AT+CIPMODE=1\r\n","OK");  //使能透传
    SendAT("AT+CIPSEND\r\n","OK");    //开始发送
  }
  //重连定时器清零，定时器0的中断函数中不断++，如果连接服务器失败，过10s后再次执行连接服务器的函数
  ESP8266.TCP_Reconnect_Timer = 0;  
}

/*
* @name   Transfer_Tempareture
* @brief  传送PCB板的温度
* @param  Tempareture：PCB板的温度值
* @retval None   
*/
static void Transfer_Tempareture(float Tempareture)
{
  static float Temp_float = 0;
  //static uint8_t Temp_uint8 = 0;
  static uint16_t Temp_uint16 = 0;

  //喂狗
  WatchDog.Feed();
  
  Temp_float = Tempareture;
  if(ESP8266.TCP_Connect_Status == TRUE)
  {
    //正负判断
    if(Temp_float < 0)
    {
      //因为是传到服务器上，并且WIFI模块已经开启透传模式，所以这里是用UART2发送数据
      UART2.UART_SendString("The tempareture of PCB is -");
      Temp_float = 0 - Temp_float;
    }
    else
    {
      UART2.UART_SendString("The tempareture of PCB is ");
    }

    //温度值，为什么要强制转换为uint16_t后赋给uint8_t的类型变量？尝试了下面两种方法，感觉教程写错了
    //Temp_uint8 = (uint16_t)Temp_float;
    //Temp_uint8 = (uint8_t)Temp_float;   //强制转换为uint8_t类型也是可以的
    Temp_uint16 = (uint16_t)Temp_float;   //直接定义变量为uint16_t类型，强制转换为uint16_t也可以
    if(Temp_uint16 < 10)
    {
      //个位数则直接将无符号整型的温度转化为字符型
      UART2.UART_SendData(Temp_uint16 + 0x30); 
    }
    else
    {
      //如果是十位数则分别求出个位和十位再转为字符型
      UART2.UART_SendData(Temp_uint16/10 + 0x30);
      UART2.UART_SendData(Temp_uint16%10 + 0x30);
    }
    //换行
    UART2.UART_SendString("\r\n");
  }
}

/*
* @name   Receive_Information
* @brief  接收的信息
* @param  None
* @retval None
*/
static void Receive_Information()
{
  if(ESP8266.TCP_Connect_Status == TRUE)
  {
    //如果串口2接收缓存中有PWM = 100%的信息
    if(strstr(UART2.pucRec_Buffer,"PWM = 100%") != NULL)
    {
      //设置占空比，调整亮度
      PWM.Duty = Duty_100;
      PWM.PWM_Duty_Set(PWM.Duty);
      //备份占空比
      PWM.IAP_Duty_Backup(IAP_PWM_DUTY_ADDR,PWM.Duty);

      //回应服务器（增加）
      UART2.UART_SendString("PWM lamp is opened!\r\n");

      //清除串口2接收缓存
      Public.Memory_Clr(UART2.pucRec_Buffer,UART2.ucRec_Cnt);
      UART2.ucRec_Cnt = 0;
    }

    //如果串口2接收缓存中有PWM = 0%的信息
    if(strstr(UART2.pucRec_Buffer,"PWM = 0%") != NULL)
    {
      //设置占空比，调整亮度
      PWM.Duty = Duty_0;
      PWM.PWM_Duty_Set(PWM.Duty);
      //备份占空比
      PWM.IAP_Duty_Backup(IAP_PWM_DUTY_ADDR,PWM.Duty);

      //回应服务器（增加）
      UART2.UART_SendString("PWM lamp is closed!\r\n");

      //清除串口2接收缓存
      Public.Memory_Clr(UART2.pucRec_Buffer,UART2.ucRec_Cnt);
      UART2.ucRec_Cnt = 0;
    }

    if(strstr(UART2.pucRec_Buffer,"shut down") != NULL)
    {
      if(System.ucSystem_Statues == System_Run)
      {
        System.ucSystem_Statues = System_Standby;
      }
      //清除串口2接收缓存
      Public.Memory_Clr(UART2.pucRec_Buffer,UART2.ucRec_Cnt);
      UART2.ucRec_Cnt = 0;
    }
  }
}
/********************************************************
  End Of File
********************************************************/